package com.heima.wemedia.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.common.constants.message.NewsAutoScanConstants;
import com.heima.common.constants.message.NewsUpOrDownConstants;
import com.heima.common.constants.wemedia.WemediaConstants;
import com.heima.common.exception.CustException;
import com.heima.model.common.dtos.PageResponseResult;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.media.dtos.WmNewsDTO;
import com.heima.model.threadlocal.WmThreadLocalUtils;
import com.heima.model.wemedia.dtos.WmNewsPageReqDTO;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.model.wemedia.pojos.WmNewsMaterial;
import com.heima.wemedia.mapper.WmMaterialMapper;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.mapper.WmNewsMaterialMapper;
import com.heima.wemedia.service.WmNewsService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Service
public class WmNewsServiceImpl extends ServiceImpl<WmNewsMapper, WmNews> implements WmNewsService {

    @Value("${file.oss.web-site}")
    private String webSite;

    @Autowired
    private WmNewsMaterialMapper wmNewsMaterialMapper;

    @Autowired
    private WmMaterialMapper wmMaterialMapper;

    @Autowired
    private RabbitTemplate rabbitTemplate;


    /**
     * 查询文章列表.
     * @param dto
     * @return
     */
    @Override
    public ResponseResult findList(WmNewsPageReqDTO dto) {

        //校验参数
        if (dto==null) {
            CustException.cust(AppHttpCodeEnum.PARAM_REQUIRE,"缺少参数");
        }
        //判断用户是否登陆
        Integer wmUserId = WmThreadLocalUtils.getUser().getId();
        if (wmUserId==null) {
            CustException.cust(AppHttpCodeEnum.NEED_LOGIN,"请先登录");
        }
        //检查分页
        dto.checkParam();

        //构建查询条件
        Page<WmNews> newsPage = new Page<>(dto.getPage(), dto.getSize());
        LambdaQueryWrapper<WmNews> queryWrapper = Wrappers.<WmNews>lambdaQuery();

//        1. 如果有文章标题，按照文章标题模糊查询
        if (dto.getKeyword()!=null) {
            queryWrapper.like(WmNews::getTitle,dto.getKeyword());
        }

//        2. 如果有频道信息，按照频道ID查询
        if (dto.getChannelId()!=null) {
            queryWrapper.eq(WmNews::getChannelId,dto.getChannelId());
        }

//        3. 如果有文章状态，按照状态信息进行查询
        if (dto.getStatus()!=null) {
            queryWrapper.eq(WmNews::getStatus,dto.getStatus());
        }

//        4. 如果开始时间，结束时间不为空按照时间区间查询
        if (dto.getBeginPubDate()!=null && dto.getEndPubDate()!=null) {
            queryWrapper.between(WmNews::getCreatedTime,dto.getBeginPubDate(),dto.getEndPubDate());
        }

//        5. 按照登录用户ID去查询
        queryWrapper.eq(WmNews::getUserId,wmUserId);

//        6. 按照创建时间降序
        queryWrapper.orderByDesc(WmNews::getCreatedTime);

//        7. 分页查询，返回结果设置host  地址 为图片访问前缀
        IPage<WmNews> pageResult = this.page(newsPage, queryWrapper);

        PageResponseResult result = new PageResponseResult(dto.getPage(), dto.getSize(), pageResult.getTotal(),pageResult.getRecords());

        //result.setData(pageResult.getRecords());
        // 处理文章图片
        result.setHost(webSite);

        return result;
    }


    /**
     * 根据ID查询文章
     * @param id
     * @return
     */
    @Override
    public ResponseResult findWmNewsById(Integer id) {
        //1.校验参数
        if (id == null) {
            CustException.cust(AppHttpCodeEnum.PARAM_INVALID);
        }
//        //判断用户是否登陆
//        Integer wmUserId = WmThreadLocalUtils.getUser().getId();
//        if (wmUserId==null) {
//            CustException.cust(AppHttpCodeEnum.NEED_LOGIN,"请先登录");
//        }
        //2.执行查询
        WmNews wmNews = this.getById(id);
        if (wmNews == null) {
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST);
        }

        //3.返回结果
        ResponseResult result = ResponseResult.okResult(wmNews);

        result.setHost(webSite);

        return result;

    }

    /**
     * 根据ID删除文章
     * @param id
     * @return
     */
    @Override
    public ResponseResult delNews(Integer id) {
        //1.校验参数
        if (id == null) {
            CustException.cust(AppHttpCodeEnum.PARAM_INVALID,"？？？");
        }
        //1.2检查用户登录状态
        Integer wmUserId = WmThreadLocalUtils.getUser().getId();
        if (wmUserId==null) {
            CustException.cust(AppHttpCodeEnum.NEED_LOGIN,"请先登录");
        }

        //1.3判断文章是否存在
        WmNews wmNews = this.getById(id);
        if (wmNews==null) {
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST,"文章不存在");
        }

        //2.判断条件，执行删除

        if (wmNews.getStatus().equals(WmNews.Status.PUBLISHED.getCode()) && wmNews.getEnable()
                .equals(WemediaConstants.WM_NEWS_UP)) {
            CustException.cust(AppHttpCodeEnum.NO_OPERATOR_AUTH,"请先下架文章");
        }

        if (wmNewsMaterialMapper.selectList(Wrappers.<WmNewsMaterial>lambdaQuery()
                .eq(WmNewsMaterial::getNewsId,wmNews.getId()))!=null) {
            int flag = wmNewsMaterialMapper.delete(Wrappers.<WmNewsMaterial>lambdaQuery()
                    .eq(WmNewsMaterial::getNewsId,wmNews.getId()));
            log.info("文章素材关联关系删除 {}",flag);

        }
        this.removeById(id);
        return ResponseResult.okResult();
    }

    /**
     * 修改文章上下架
     * @param dto
     * @return
     */
    @Override
    public ResponseResult downOrUp(WmNewsDTO dto) {
        //1.检查参数
        if(dto == null || dto.getId() == null){
            CustException.cust(AppHttpCodeEnum.PARAM_INVALID);
        }
        //1.2检查用户登录状态
        Integer wmUserId = WmThreadLocalUtils.getUser().getId();
        if (wmUserId==null) {
            CustException.cust(AppHttpCodeEnum.NEED_LOGIN,"请先登录");
        }
        //1.2检查上下架参数
        Short enable = dto.getEnable();
        if(enable == null ||
                (!WemediaConstants.WM_NEWS_UP.equals(enable)&&!WemediaConstants.WM_NEWS_DOWN.equals(enable))){
            CustException.cust(AppHttpCodeEnum.PARAM_INVALID,"上下架状态错误");
        }
        //2.查询文章
        WmNews wmNews = getById(dto.getId());
        if(wmNews == null){
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST,"文章不存在");
        }
        //3.判断文章是否发布
        if(!wmNews.getStatus().equals(WmNews.Status.PUBLISHED.getCode())){
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST,"当前文章不是发布状态，不能上下架");
        }
        //4.修改文章状态，同步到app端（后期做）TODO
        update(Wrappers.<WmNews>lambdaUpdate().eq(WmNews::getId,dto.getId())
                .set(WmNews::getEnable,dto.getEnable()));


        //5. 上下架发送消息通知  用于同步article 及 elasticsearch
        if (wmNews.getArticleId()!=null) {
            if(enable.equals(WemediaConstants.WM_NEWS_UP)){
                // 上架消息
                rabbitTemplate.convertAndSend(NewsUpOrDownConstants.NEWS_UP_OR_DOWN_EXCHANGE,
                        NewsUpOrDownConstants.NEWS_UP_ROUTE_KEY,wmNews.getArticleId());
            }else {
                // 下架消息
                rabbitTemplate.convertAndSend(NewsUpOrDownConstants.NEWS_UP_OR_DOWN_EXCHANGE,
                        NewsUpOrDownConstants.NEWS_DOWN_ROUTE_KEY,wmNews.getArticleId());
            }
        }
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);

    }


    /**
     * 保存或修改文章信息
     * @param dto
     * @return
     */
    @Override
    public ResponseResult submitNews(WmNewsDTO dto) {

        //1.检查参数 封装返回WmNes对象
        WmNews wmNews = parseDtoToWmNews(dto);

        //2.保存或修改
        saveOrUpdateWmNews(wmNews);

        // 如果是草稿  直接返回
        if (WemediaConstants.WM_NEWS_DRAFT_STATUS.equals(dto.getStatus())){
            return ResponseResult.okResult();
        }

        //3.保存 内容、封面 和 素材的关联关系

        //3.1 解析内容，得到素材路径的集合
        String content = wmNews.getContent();
        List<String> paths = parseContentImages(content);

        //3.2 保存内容图片 与 素材的关联关系
        if (paths.size()!=0) {
            saveRelativeInfo(paths,wmNews, WemediaConstants.WM_CONTENT_REFERENCE);
        }

        //3.3 保存封面内容 与 素材的关联关系

        saveRelativeInfoForCover(dto,paths,wmNews);


        // 3.4 TODO 发送待审核消息 (简单队列模式)
        rabbitTemplate.convertAndSend(NewsAutoScanConstants.WM_NEWS_AUTO_SCAN_QUEUE,wmNews.getId());
        log.info("成功发送 待审核消息 ==> 队列:{}, 文章id:{}",NewsAutoScanConstants.WM_NEWS_AUTO_SCAN_QUEUE,wmNews.getId());

        return ResponseResult.okResult();
    }

    //保存封面和素材的关联关系
    private void saveRelativeInfoForCover( WmNewsDTO dto,List<String> paths, WmNews wmNews) {

        if (dto.getType()!=0) {

            List<String> images1 = dto.getImages();//http...jpg

            if (dto.getType()== -1) {
                //从内容中自动生成封面
                if (paths!=null) {
                    if (paths.size()<=2 && paths.size()>0) {
                        images1 = paths.stream().limit(1).collect(Collectors.toList());
                        wmNews.setType(WemediaConstants.WM_NEWS_SINGLE_IMAGE);
                    }else if (paths.size()>2) {
                        images1 = paths.stream().limit(3).collect(Collectors.toList());
                        wmNews.setType(WemediaConstants.WM_NEWS_MANY_IMAGE);
                    }else {
                        wmNews.setType(WemediaConstants.WM_NEWS_NONE_IMAGE);
                    }
                    if (images1 != null && images1.size() > 0) {
                        // 将图片集合 转为字符串  url1,url2,url3
                        wmNews.setImages(imagesToStr(images1));
                    }
                    //修改文章表
                    updateById(wmNews);
                }
            }

            if (images1 != null && images1.size() > 0) {
                images1 = images1.stream().map(x->x.replace(webSite,"")
                        .replace(" ","")).collect(Collectors.toList());
                saveRelativeInfo(images1, wmNews, WemediaConstants.WM_IMAGE_REFERENCE);
            }

        }
    }

    //保存关联关系到数据库 通用方法
    private void saveRelativeInfo(List<String> paths, WmNews wmNews, short type) {
    //调用素材表接口，根据素材路径集合，查询得到素材ID集合
        List<Integer> ids = wmMaterialMapper.selectRelationsIds(paths, wmNews.getUserId());

        //2 判断素材是否缺失
        if(CollectionUtils.isEmpty(ids) || ids.size() < paths.size()){
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST,"相关素材缺失,保存文章失败");
        }
        wmNewsMaterialMapper.saveRelations(ids,wmNews.getId(),type);


    }

    //解析内容得到图片地址
    private List<String> parseContentImages(String content) {
        List<Map> maps = JSON.parseArray(content, Map.class);
        return maps.stream()
                .filter(map -> map.get("type").equals("image"))
                .map(x -> x.get("value").toString())
                .map(url -> url.replace(webSite,"").replaceAll(" ",""))
                .distinct()
                .collect(Collectors.toList());

    }

    /**
     * 保存或修改
     * @param wmNews
     */
    private void saveOrUpdateWmNews(WmNews wmNews) {
        //信息补全
        wmNews.setCreatedTime(new Date());
        wmNews.setSubmitedTime(new Date());
        //上下架，默认上架
        wmNews.setEnable(WemediaConstants.WM_NEWS_UP);
        //根据是否有文章id判断 ， 有则修改 没有则保存
        if (wmNews.getId()==null) {
            this.save(wmNews);
        }else {
            // 修改前 先要删除关联关系,再保存
            wmNewsMaterialMapper.delete(Wrappers.<WmNewsMaterial>lambdaQuery()
                    .eq(WmNewsMaterial::getNewsId,wmNews.getId()));
            this. updateById(wmNews);
        }
    }

    /**
     * 检查参数 封装返回WmNes对象
     * @param dto
     * @return
     */
    private WmNews parseDtoToWmNews(WmNewsDTO dto) {
        if (dto==null) {
            CustException.cust(AppHttpCodeEnum.PARAM_REQUIRE,"缺少参数");
        }
        //判断用户是否登陆
        Integer wmUserId = WmThreadLocalUtils.getUser().getId();
        if (wmUserId==null) {
            CustException.cust(AppHttpCodeEnum.NEED_LOGIN,"请先登录");
        }

        //将参数属性封装到wmNes对象中
        WmNews wmNews = new WmNews();
        BeanUtils.copyProperties(dto,wmNews);

        //需要特殊处理的字段type，-1保存到数据库会报错
        if (dto.getType().equals(WemediaConstants.WM_NEWS_TYPE_AUTO)) {
            wmNews.setType(null);
        }

        //需要特殊处理的字段images,前端穿的是集合,后端接受的是字符串
        if (CollectionUtils.isNotEmpty(dto.getImages())) {
            wmNews.setImages(imagesToStr(dto.getImages()));//自定义imagesToStr方法
        }

        //设置用户Id
        wmNews.setUserId(wmUserId);

        return wmNews;
    }

    //将字符串集合 转化为 字符串用逗号拼接
    private String imagesToStr(List<String> images) {
        String s = images.stream()
                .map(image -> image.replaceAll(webSite, ""))
                .collect(Collectors.joining(","));
        return s;
    }
}
